﻿using System;
using System.IO;
using System.Net;
using System.Text;
using System.Timers;
using Vepa.Server.Config;
using Vepa.Server.Database;
using Vepa.Shared;
using log4net;

namespace Vepa.Server
{
    static class VepaManager
    {
        #region Fields
        /// <summary>
        /// If enabled, the VepaManger will get a new Vepa version in a certain interval.
        /// </summary>
        public static bool AutoUpdate
        {
            get { return _autoupdate; }
            set
            {
                _autoupdate = value;
                if (_autoupdate)
                    updateTimer.Enabled = true;
                else
                    updateTimer.Enabled = false;
            }
        }
        private static bool _autoupdate;

        private static readonly ILog log = LogManager.GetLogger(typeof(VepaManager));
        /// <summary>
        /// The interval in which the VepaManger shall check for a new version.
        /// </summary>
        public static int UpdateInterval
        {
            get { return _updateinterval; }
            set
            {
                _updateinterval = value;
                //Do we need to restart the timer here?
                updateTimer.Enabled = false;
                updateTimer.Interval = value;
                updateTimer.Enabled = true;
            }
        }
        private static int _updateinterval;


        static Timer updateTimer;

        static IDatabase db;
        #endregion

        #region Methods
        /// <summary>
        /// Initializes the VepaManager. Has to be done before trying to do anything else with the manager.
        /// </summary>
        public static void Init()
        {
            log.Info("Initializing VepaManager");
            db = new SQLite();
            db.Open();

            if (!Directory.Exists("pdf"))
                Directory.CreateDirectory("pdf");

            updateTimer = new Timer();
            updateTimer.Interval = 5000;
            updateTimer.Elapsed += new ElapsedEventHandler(UpdateTimerEvent);
        }
        /// <summary>
        /// Returns a Vepa with a given version number.
        /// </summary>
        /// <param name="version">The version of the Vepa to return.</param>
        /// <returns>Vepa with given version</returns>
        public static VepaPDF getVepa(int version)
        {
            VepaPDF vepa = new VepaPDF();
            vepa.Info = db.getVepaInfo(version);
            
            StringBuilder path = new StringBuilder(9);
            path.Append(ConfigManager.config.PDFLocation);
            path.Append(version);
            path.Append(".pdf");

            try
            {
                if (File.Exists(path.ToString()))
                {
                    using (FileStream fs = new FileStream(path.ToString(), FileMode.Open))
                    {
                        BinaryReader br = new BinaryReader(fs);
                        vepa.Data = Convert.ToBase64String(br.ReadBytes((int)fs.Length));
                        br.Close();
                        fs.Close();
                        vepa.FileAvailable = true;
                    }
                }
                else
                {
                    vepa.FileAvailable = false;
                    throw new FileNotFoundException();
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.ToString());

            }
            return vepa;
        }

        /// <summary>
        /// Returns all VepaInfos from the Database
        /// </summary>
        /// <returns>All VepaInfos</returns>
        public static VepaInfo[] getAllVepaInfos()
        {
            return db.getAllVepaInfos();
        }

        /// <summary>
        /// Downloads a new Vepa from the bbs|me server
        /// </summary>
        public static void updateVepa()
        {
            log.Info("Downloading new Vepa");
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(ConfigManager.config.ServerUri);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream responseStream = response.GetResponseStream();

            DateTime dt = DateTime.ParseExact(response.Headers["Date"], "r", System.Globalization.CultureInfo.InvariantCulture);
            log.Debug(dt.GetDateTimeFormats('r', System.Globalization.CultureInfo.InvariantCulture)[0]);
            int bufferSize = 1024;
            byte[] buffer = new byte[bufferSize];
            int bytesRead = 0;

            int version = Directory.GetFiles(ConfigManager.config.PDFLocation).Length;
            StringBuilder path = new StringBuilder(9);
            path.Append(ConfigManager.config.PDFLocation);
            path.Append(version);
            path.Append(".pdf");

            FileStream fileStream = File.Create(path.ToString());
            while ((bytesRead = responseStream.Read(buffer, 0, bufferSize)) != 0)
            {
                fileStream.Write(buffer, 0, bytesRead);
            }
            fileStream.Close();

            VepaInfo info = new VepaInfo();
            VepaInfo latestInfo = db.getLatestVepaInfo();
            if (latestInfo != null)
                info.Version = db.getLatestVepaInfo().Version + 1;
            else
                info.Version = 0;
            info.ReleaseDateTime = dt;

            
            System.IO.FileStream FileCheck = System.IO.File.OpenRead(path.ToString());
            
            System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
            System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
            info.PdfHash = enc.GetString(md5.ComputeHash(FileCheck));           
            FileCheck.Close();

               
            db.createVepaInfo(info);
        }

        private static DateTime CurrentVepaDateTime()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(ConfigManager.config.ServerUri);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            DateTime dt =  DateTime.ParseExact(response.Headers["Date"], "r", System.Globalization.CultureInfo.InvariantCulture);
            response.Close();
            response.Dispose();
            return dt;
        }
        #endregion

        #region Eventhandler
        public static void UpdateTimerEvent(object source, ElapsedEventArgs e)
        {
            VepaInfo latestInfo = db.getLatestVepaInfo();
			if (latestInfo != null)
			{
			//info.Version = db.getLatestVepaInfo().Version + 1;


            log.Info("Checking for new Vepa.");
            //Log.Debug(latestInfo.ReleaseDateTime.Ticks);
            //Log.Debug(CurrentVepaDateTime().Ticks);
            
            if (latestInfo.ReleaseDateTime.Ticks < CurrentVepaDateTime().Ticks)            
                updateVepa();            
			}
			else
			{
				updateVepa();
			}
        }
        #endregion
    }
}
